package com.yf.exam.modules.user.cert.job;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yf.exam.ability.job.service.JobService;
import com.yf.exam.modules.user.cert.entity.UserCert;
import com.yf.exam.modules.user.cert.service.UserCertService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 证书资源清理定时任务
 * 场景三：资源清理
 * 定期清理过期的临时文件、失效的证书记录等
 * 
 * @author system
 */
@Slf4j
@Component
public class CertCleanupJob implements Job {

    @Autowired
    private UserCertService userCertService;
    
    @Value("${cert.upload.path:/upload/certs}")
    private String certUploadPath;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail detail = jobExecutionContext.getJobDetail();
        String name = detail.getKey().getName();
        String group = detail.getKey().getGroup();
        String data = String.valueOf(detail.getJobDataMap().get(JobService.TASK_DATA));

        log.info("++++++++++定时任务：证书资源清理");
        log.info("++++++++++jobName:{}", name);
        log.info("++++++++++jobGroup:{}", group);
        log.info("++++++++++taskData:{}", data);

        try {
            // 1. 清理长时间处于生成中状态的记录（超过2小时）
            cleanupStuckGeneratingRecords();
            
            // 2. 清理过期的失败记录（超过30天）
            cleanupExpiredFailedRecords();
            
            // 3. 清理孤立的证书文件（文件存在但数据库记录不存在）
            cleanupOrphanedCertFiles();
            
            log.info("证书资源清理任务完成");
            
        } catch (Exception e) {
            log.error("证书资源清理任务执行异常", e);
            throw new JobExecutionException(e);
        }
    }

    /**
     * 清理长时间处于生成中状态的记录
     */
    private void cleanupStuckGeneratingRecords() {
        try {
            // 查询超过2小时还在生成中的记录
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.HOUR_OF_DAY, -2);
            Date twoHoursAgo = calendar.getTime();
            
            QueryWrapper<UserCert> wrapper = new QueryWrapper<>();
            wrapper.eq("status", UserCert.STATUS_GENERATING)
                   .le("update_time", twoHoursAgo);
            
            List<UserCert> stuckRecords = userCertService.list(wrapper);
            
            if (!stuckRecords.isEmpty()) {
                log.info("发现 {} 个长时间处于生成中状态的记录，将标记为失败", stuckRecords.size());
                
                for (UserCert record : stuckRecords) {
                    record.setStatus(UserCert.STATUS_FAILED);
                    record.setUpdateTime(new Date());
                    userCertService.updateById(record);
                    
                    log.debug("标记为失败：userId={}, examId={}", record.getUserId(), record.getExamId());
                }
                
                log.info("已处理 {} 个卡住的生成记录", stuckRecords.size());
            } else {
                log.info("没有发现卡住的生成记录");
            }
            
        } catch (Exception e) {
            log.error("清理卡住的生成记录时发生异常", e);
        }
    }

    /**
     * 清理过期的失败记录
     */
    private void cleanupExpiredFailedRecords() {
        try {
            // 删除30天前的失败记录
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH, -30);
            Date thirtyDaysAgo = calendar.getTime();
            
            QueryWrapper<UserCert> wrapper = new QueryWrapper<>();
            wrapper.eq("status", UserCert.STATUS_FAILED)
                   .le("update_time", thirtyDaysAgo);
            
            List<UserCert> expiredRecords = userCertService.list(wrapper);
            
            if (!expiredRecords.isEmpty()) {
                log.info("发现 {} 个过期的失败记录，将进行删除", expiredRecords.size());
                
                boolean removed = userCertService.remove(wrapper);
                if (removed) {
                    log.info("已删除 {} 个过期的失败记录", expiredRecords.size());
                } else {
                    log.warn("删除过期失败记录时出现问题");
                }
            } else {
                log.info("没有发现过期的失败记录");
            }
            
        } catch (Exception e) {
            log.error("清理过期失败记录时发生异常", e);
        }
    }

    /**
     * 清理孤立的证书文件
     */
    private void cleanupOrphanedCertFiles() {
        try {
            File certDir = new File(certUploadPath);
            if (!certDir.exists() || !certDir.isDirectory()) {
                log.info("证书目录不存在或不是目录：{}", certUploadPath);
                return;
            }
            
            log.info("开始扫描证书目录：{}", certUploadPath);
            
            int orphanedCount = 0;
            int checkedCount = 0;
            
            // 递归扫描证书目录
            orphanedCount += scanAndCleanDirectory(certDir, checkedCount);
            
            log.info("证书文件扫描完成，检查了 {} 个文件，清理了 {} 个孤立文件", checkedCount, orphanedCount);
            
        } catch (Exception e) {
            log.error("清理孤立证书文件时发生异常", e);
        }
    }

    /**
     * 递归扫描并清理目录
     */
    private int scanAndCleanDirectory(File dir, int checkedCount) {
        int orphanedCount = 0;
        
        File[] files = dir.listFiles();
        if (files == null) {
            return orphanedCount;
        }
        
        for (File file : files) {
            if (file.isDirectory()) {
                // 递归处理子目录
                orphanedCount += scanAndCleanDirectory(file, checkedCount);
            } else if (file.isFile() && file.getName().toLowerCase().endsWith(".pptx")) {
                // 检查证书文件
                checkedCount++;
                
                String filePath = file.getAbsolutePath();
                String relativePath = filePath.replace(certUploadPath, "").replace("\\", "/");
                if (relativePath.startsWith("/")) {
                    relativePath = relativePath.substring(1);
                }
                
                // 查询数据库中是否存在对应记录
                QueryWrapper<UserCert> wrapper = new QueryWrapper<>();
                wrapper.like("cert_url", relativePath)
                       .eq("status", UserCert.STATUS_GENERATED);
                
                long count = userCertService.count(wrapper);
                
                if (count == 0) {
                    // 文件存在但数据库中没有对应记录，且文件创建时间超过1天
                    long fileAge = System.currentTimeMillis() - file.lastModified();
                    if (fileAge > 24 * 60 * 60 * 1000) { // 超过1天
                        try {
                            if (file.delete()) {
                                orphanedCount++;
                                log.debug("删除孤立证书文件：{}", filePath);
                            } else {
                                log.warn("无法删除孤立证书文件：{}", filePath);
                            }
                        } catch (Exception e) {
                            log.error("删除孤立证书文件时发生异常：{}", filePath, e);
                        }
                    }
                }
            }
        }
        
        return orphanedCount;
    }
}